package com.mallcai.bigdata.ladon.service.system.impl;

import com.cake.bigdata.starter.exception.category.BusinessException;
import com.mallcai.bigdata.ladon.dpl.entity.system.Resource;
import com.mallcai.bigdata.ladon.dpl.entity.system.RoleRlResource;
import com.mallcai.bigdata.ladon.dpl.mapper.system.ResourceMapper;
import com.mallcai.bigdata.ladon.dpl.mapper.system.RoleRlResourceMapper;
import com.mallcai.bigdata.ladon.service.system.IResService;
import com.mallcai.bigdata.ladon.vo.system.TreeNodeVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.util.Assert;

import java.util.*;

/**
 * Created by oneape<oneape15@163.com>
 * Created 2019-06-24 13:53.
 * Modify:
 */
@Slf4j
@Service
public class ResService implements IResService {
    @Autowired
    private ResourceMapper       resourceMapper;
    @Autowired
    private RoleRlResourceMapper roleRlResourceMapper;

    /**
     * 根据条件查询资源列表
     *
     * @param params Map
     * @return List
     */
    @Override
    public List<Resource> getByParams(Map<String, Object> params) {
        return resourceMapper.getByParams(params);
    }

    /**
     * 获取子节点列表
     *
     * @param parentIds List
     * @return List
     */
    @Override
    public List<Resource> getChildren(List<Long> parentIds) {
        return resourceMapper.getChildren(parentIds);
    }

    /**
     * 获取资源树
     *
     * @param needRoot int 是否需要根节点
     * @return List
     */
    @Override
    public List<TreeNodeVo> getResTree(boolean needRoot) {
        // 根据父节点id进行排序
        List<Resource> resources = resourceMapper.getAllRes();

        List<TreeNodeVo> nodes = new ArrayList<>();

        // 这里只有二级树,简单处理
        if (resources != null && resources.size() >= 0) {
            Map<Integer, List<Resource>> levelMap = new HashMap<>();
            int maxLevel = 1;
            for (Resource r : resources) {
                int level = r.getLevel();
                if (maxLevel < level) {
                    maxLevel = level;
                }

                if (!levelMap.containsKey(level)) {
                    levelMap.put(level, new ArrayList<>());
                }
                levelMap.get(level).add(r);
            }

            // 从最深的分支开始向根节点递归
            Map<Long, List<TreeNodeVo>> preNode = new LinkedHashMap<>();
            for (int i = maxLevel; i > 0; i--) {
                Map<Long, List<TreeNodeVo>> curNode = new LinkedHashMap<>();

                List<Resource> tmp = levelMap.get(i);
                if (tmp == null) {
                    continue;
                }

                for (Resource r : tmp) {
                    TreeNodeVo node = new TreeNodeVo(String.valueOf(r.getId()), r.getName(), r.getIcon());
                    if (preNode.containsKey(r.getId())) {
                        node.setChildren(preNode.get(r.getId()));
                        node.setLeaf(false);
                    } else {
                        node.setLeaf(true); // 没有子节点即为叶子节点
                    }
                    if (!curNode.containsKey(r.getParentId())) {
                        curNode.put(r.getParentId(), new ArrayList<>());
                    }
                    curNode.get(r.getParentId()).add(node);
                }

                preNode = curNode;
            }

            List<TreeNodeVo> tmps = new ArrayList<>();
            preNode.values().forEach(list -> tmps.addAll(list));
            if (needRoot) {
                TreeNodeVo root = new TreeNodeVo("0", "---根节点---", "bars");
                root.setChildren(tmps);
                nodes.add(root);
            } else {
                nodes = tmps;
            }
        }

        return nodes;
    }

    /**
     * 获取所有资源
     *
     * @return List
     */
    @Override
    public List<Resource> getAllResource() {
        return resourceMapper.getAllRes();
    }

    /**
     * 添加资源
     *
     * @param res Resource
     * @return int
     */
    @Override
    public int addResource(Resource res) {
        Assert.isTrue(StringUtils.isNotBlank(res.getName()), "资源名为空");

        // 检测
        levelCheck(res);
        typeCheck(res);

        List<Resource> ress = resourceMapper.hasSame(res.getName(), res.getPath());
        if (ress != null && ress.size() > 0) {
            throw new BusinessException("资源名或资源编码已存在");
        }
        return resourceMapper.insert(res);
    }

    private void levelCheck(Resource res) {
        Long parentId = res.getParentId();
        if (parentId != null && parentId > 0) {
            Resource tmp = resourceMapper.getById(parentId);
            if (tmp == null) {
                throw new BusinessException("依赖的父节点不存在");
            }
            res.setLevel(tmp.getLevel() + 1);
        } else {
            res.setParentId(0L);
            res.setLevel(1);
        }
    }

    private void typeCheck(Resource res) {
        Assert.isTrue(res.getType() != null, "资源类型为空");
        if (res.getType() == 0) {
            res.setAuthCode(null);
            if (StringUtils.isBlank(res.getPath())) {
                throw new BusinessException("资源路径不能为空");
            }
        } else {
            res.setType(1);
            res.setPath(null);
            if (StringUtils.isBlank(res.getAuthCode())) {
                throw new BusinessException("资源权限编码不能为空");
            }
        }
    }


    /**
     * 修改资源
     *
     * @param res Resource
     * @return int
     */
    @Override
    public int updateResource(Resource res) {
        Assert.isTrue(res.getId() != null, "资源主键为空");
        Assert.isTrue(StringUtils.isNotBlank(res.getName()), "资源名为空");

        // 检测
        levelCheck(res);
        typeCheck(res);

        List<Resource> ress = resourceMapper.hasSame(res.getName(), res.getPath());
        if (ress != null && ress.size() > 0) {
            for (Resource r : ress) {
                if (!r.getId().equals(res.getId())) {
                    throw new BusinessException("资源名或资源编码已存在");
                }
            }
        }
        return resourceMapper.update(res);
    }

    /**
     * 删除资源
     *
     * @param res Resource
     * @return int
     */
    @Override
    public int deleteResource(Resource res) {
        if (resourceMapper.hasChildren(res.getId()) > 0) {
            throw new BusinessException("该资源还存在子节点,不允许被删除~");
        }
        return resourceMapper.delete(res);
    }

    /**
     * 根据用户Id获取拥有的权限列表
     *
     * @param userId Long 用户Id
     * @return List
     */
    @Override
    public List<String> getAuthCodeByUserId(Long userId) {
        List<String> authCodes = new ArrayList<>();
        List<Resource> allRes = resourceMapper.getAllSimpleRes();
        Map<Long, Resource> map = new HashMap<>();
        if (allRes != null) {
            allRes.forEach(r -> map.put(r.getId(), r));
        }

        List<Long> children = new ArrayList<>();
        List<Resource> res = resourceMapper.getAuthCodeByUserId(userId);
        if (res != null && res.size() > 0) {
            for (Resource r : res) {
                authCodes.add(r.getAuthCode());
                children.add(r.getId());
            }
        }

        // 获取父节点的权限code
        while (children.size() > 0) {
            Set<Long> tmp = new HashSet<>();
            Set<String> set = new HashSet<>();
            children.forEach(id -> {
                if (map.containsKey(id)) {
                    Resource r = map.get(id);
                    if (r.getParentId() != null && r.getParentId() > 0) {
                        Resource parent = map.get(r.getParentId());
                        if (parent != null) {
                            tmp.add(parent.getId());
                            if (StringUtils.isNotBlank(parent.getAuthCode())) {
                                set.add(parent.getAuthCode());
                            }
                        }
                    }
                }
            });
            children = new ArrayList<>(tmp);
            authCodes.addAll(set);
        }
        return authCodes;
    }

    /**
     * 根据用户获取拥有的操作权限列表
     *
     * @param userId Long
     * @return List
     */
    @Override
    public List<RoleRlResource> getOptPermissionByUserId(Long userId) {
        return roleRlResourceMapper.getOptResourceInfo(userId);
    }
}
